package com.orange.core.service.activity.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.service.WxPayService;
import com.orange.core.config.wx.WxProperty;
import com.orange.core.mapper.activity.ActivityMapper;
import com.orange.core.mapper.user.UserMapper;
import com.orange.core.pojo.PageReqDto;
import com.orange.core.pojo.entity.activity.Activity;
import com.orange.core.pojo.entity.activity.dto.ActivityDTO;
import com.orange.core.pojo.entity.activity.dto.ActivityRegistrationAuditDTO;
import com.orange.core.pojo.entity.activity.dto.ActivityRegistrationOrder;
import com.orange.core.pojo.entity.activity.vo.ActivityVO;
import com.orange.core.pojo.entity.activity.vo.RegistrationVO;
import com.orange.core.pojo.entity.activityRegistration.ActivityRegistration;
import com.orange.core.pojo.entity.activityRegistration.dto.ActivityRegistrationDTO;
import com.orange.core.pojo.entity.activityRegistration.vo.ActivityRegistrationExcel;
import com.orange.core.pojo.entity.activityRegistration.vo.ActivityRegistrationVO;
import com.orange.core.pojo.entity.credit.CreditFlow;
import com.orange.core.pojo.entity.user.User;
import com.orange.core.pojo.enums.*;
import com.orange.core.pojo.req.activity.ActivityPageReq;
import com.orange.core.pojo.req.activityRegistrations.ActivityRegistrationPageReq;
import com.orange.core.pojo.rsp.activity.ActivityOrderPayRsp;
import com.orange.core.pojo.rsp.activity.ActivityOrderRsp;
import com.orange.core.service.activity.ActivityService;
import com.orange.core.service.activityRegistration.ActivityRegistrationService;
import com.orange.core.service.credit.CreditFlowService;
import com.orange.core.service.user.UserService;
import com.orange.core.util.*;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>ClassName:ActivityServiceImpl</p>
 * <p>Description: 活动管理impl</p>
 * <p>Author: lwm</p>
 * <p>Date: 2025/5/22 23:30</p>
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class ActivityServiceImpl extends ServiceImpl<ActivityMapper, Activity> implements ActivityService {

    private static final int MAX_HOT_ACTIVITIES = 4; // 最大热门活动数量

    private static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ofPattern("yyyy.MM.dd");

    private static final String ACTIVITY_ORDER_PREFIX = "activity:order:%s:%s";
    private static final String PAY_NOTIFY_LOCK = "pay_notify_lock";
    private static final String REFUND_NOTIFY_LOCK = "refund_notify_lock";

    private final StringRedisTemplate redisTemplate;
    private final ObjectMapper objectMapper;

    private final ActivityRegistrationService activityRegistrationService;
    private final UserService userService;
    private final UserMapper userMapper;

    private final CreditFlowService creditFlowService;
    private final RedissonClient redissonClient;
    private final WxPayService wxPayService;
    private final WxProperty wxProperty;

    @Override
    public Page<ActivityVO> page(PageReqDto<ActivityPageReq> pageReqDto) {
        if (pageReqDto == null) {
            pageReqDto = new PageReqDto<>();
            pageReqDto.setCondition(new ActivityPageReq());
        } else if (pageReqDto.getCondition() == null) {
            pageReqDto.setCondition(new ActivityPageReq());
        }
        ActivityPageReq condition = pageReqDto.getCondition();
        Page<Activity> page = new Page<>(pageReqDto.getPage(), pageReqDto.getSize());
        LambdaQueryWrapper<Activity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StrUtil.isNotBlank(condition.getTitle()), Activity::getTitle, condition.getTitle())
                .eq(condition.getIsHot() != null, Activity::getIsHot, condition.getIsHot())
                .orderByDesc(Activity::getId);
        page = this.page(page, queryWrapper);
        List<ActivityVO> activityVOS = page.getRecords().stream().map(activity -> {
            ActivityVO activityVO = new ActivityVO();
            BeanUtil.copyProperties(activity, activityVO);
            return activityVO;
        }).collect(Collectors.toList());
        Page<ActivityVO> activityVOPage = new Page<>(pageReqDto.getPage(), pageReqDto.getSize(), page.getTotal());
        activityVOPage.setRecords(activityVOS);
        return activityVOPage;
    }


    @Override
    public ActivityVO info(int id) {
        Activity activity = this.getById(id);
        Assert.notNull(activity, "活动不存在");
        ActivityVO activityVO = new ActivityVO();
        BeanUtil.copyProperties(activity, activityVO);
        return activityVO;
    }

    @Override
    @Transactional
    public boolean save(ActivityDTO activityDTO) {
        //活动名额为空，设置为不限
        if (StrUtil.isEmpty(activityDTO.getQuota())) {
            activityDTO.setQuota("不限");
        }
        Activity activity = new Activity();
        BeanUtil.copyProperties(activityDTO, activity);
        LocalDate endTime = activityDTO.getEndTime();
        LocalDateTime end = endTime.atTime(23,59,59);
        activity.setEndTime(end);
        boolean result = this.save(activity);
        return result;
    }

    @Override
    @Transactional
    public boolean update(ActivityDTO activityDTO) {
        Activity activity = new Activity();
        BeanUtil.copyProperties(activityDTO, activity);
        LocalDate endTime = activityDTO.getEndTime();
        LocalDateTime end = endTime.atTime(23, 59, 59);
        activity.setEndTime(end);
        boolean result = this.updateById(activity);
        return result;
    }

    @Override
    @Transactional
    public boolean deleteActivityByIds(Integer[] ids) {
        boolean result = this.removeBatchByIds(Arrays.asList(ids));
        return result;
    }

    /**
     * 报名活动
     *
     * @param activityRegistrationDTO
     * @return
     */
    @Override
    public Boolean registerActivity(ActivityRegistrationDTO activityRegistrationDTO) {
        //检查是否已报名
        LambdaQueryWrapper<ActivityRegistration> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ActivityRegistration::getActivityId, activityRegistrationDTO.getActivityId())
                .eq(ActivityRegistration::getUserId, activityRegistrationDTO.getUserId());
        Assert.isFalse(activityRegistrationService.count(queryWrapper) > 0, "已报名");

        //检查活动信息
        Activity activity = this.getById(activityRegistrationDTO.getActivityId());

        //检查活动名额
        String quota = activity.getQuota();
        int registered = activity.getRegistered() != null ? activity.getRegistered() : 0;
        //当前报名人数 + 新增人数
        int totalAfterRegistration = registered + activityRegistrationDTO.getNumber();
        if (!"不限".equals(quota)) {
            //最大报名人数
            int maxParticipants = Integer.parseInt(quota);
            Assert.isFalse(totalAfterRegistration > maxParticipants,
                    "活动名额已满");
        }
        //保存报名信息
        ActivityRegistration activityRegistration = new ActivityRegistration();
        BeanUtil.copyProperties(activityRegistrationDTO, activityRegistration);
        boolean result = activityRegistrationService.save(activityRegistration);
        if (result) {
            //更新活动报名人数
            activity.setRegistered(totalAfterRegistration);
            this.updateById(activity);
        }
        return result;
    }

    @Override
    public Page<ActivityRegistrationVO> getUserRegistrations(PageReqDto<ActivityRegistrationPageReq> pageReqDto) {
        if (pageReqDto == null) {
            pageReqDto = new PageReqDto<>();
            pageReqDto.setCondition(new ActivityRegistrationPageReq());
        } else if (pageReqDto.getCondition() == null) {
            pageReqDto.setCondition(new ActivityRegistrationPageReq());
        }

        ActivityRegistrationPageReq condition = pageReqDto.getCondition();
        Page<ActivityRegistration> page = new Page<>(pageReqDto.getPage(), pageReqDto.getSize());
        LambdaQueryWrapper<ActivityRegistration> activityRegistrationQuery = new LambdaQueryWrapper<>();
        if (condition.getUserId() != null) {
            activityRegistrationQuery.eq(ActivityRegistration::getUserId, condition.getUserId());
        }
        if (condition.getActivityId() != null) {
            activityRegistrationQuery.eq(ActivityRegistration::getActivityId, condition.getActivityId());
        }
        activityRegistrationQuery.orderByDesc(ActivityRegistration::getId);
        page = activityRegistrationService.page(page, activityRegistrationQuery);
        //获取活动id
        /*List<Integer> activityIds = page.getRecords().stream()
                .map(ActivityRegistration::getActivityId)
                .distinct().collect(Collectors.toList());*/
        if(page.getRecords().isEmpty()){
            return new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
        }
        //根据活动id查询活动信息
        /*Map<Integer, Activity> integerActivityMap = this.listByIds(activityIds).stream()
                .collect(Collectors.toMap(Activity::getId, Function.identity()));*/
        List<Integer> activityIds = page.getRecords().stream()
                .map(ActivityRegistration::getActivityId)
                .distinct().collect(Collectors.toList());

        Map<Integer, Activity> activityMap = activityIds.isEmpty()
                ? Collections.emptyMap()
                : this.listByIds(activityIds).stream()
                .collect(Collectors.toMap(Activity::getId, Function.identity()));

        //封装返回结果
        List<ActivityRegistrationVO> voList = page.getRecords().stream().map(registration -> {
            ActivityRegistrationVO vo = new ActivityRegistrationVO();
            BeanUtil.copyProperties(registration, vo);

            Activity activity = activityMap.get(registration.getActivityId());
            if (activity != null) {
                vo.setActivityTitle(activity.getTitle());
                vo.setActivityAddress(activity.getActivityAddress());
                vo.setCoverImage(activity.getCoverImage());
                vo.setActivityTime(formatTimeRange(activity.getStartTime(), activity.getEndTime()));
            }
            return vo;
        }).collect(Collectors.toList());
        Page<ActivityRegistrationVO> result = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
        result.setRecords(voList);
        return result;
    }


    @Override
    public Boolean cancelRegistration(Integer registrationId, Integer userId) {
        //检查是否
        LambdaQueryWrapper<ActivityRegistration> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ActivityRegistration::getActivityId, registrationId)
                .eq(ActivityRegistration::getUserId, userId);
        ActivityRegistration registration = activityRegistrationService.getOne(queryWrapper);
        Assert.notNull(registration, "报名信息不存在");
        Assert.isFalse(registration.getStatus().getCode()
                .equals(RegistrationEnum.CANCELLED.getCode()), "已取消报名,请勿重复操作");
        registration.setStatus(RegistrationEnum.CANCELLED);

        boolean result = activityRegistrationService.updateById(registration);
        if (result) {
            //更新活动报名人数
            Activity activity = this.getById(registration.getActivityId());
            if (activity != null) {
                activity.setRegistered(activity.getRegistered() - 1);
            }
            this.updateById(activity);
        }
        return result;
    }

    @Override
    public Boolean setHotActivity(Integer activityId, Integer isHot) {
        Activity activity = this.getById(activityId);
        Assert.notNull(activity, "活动不存在");
        activity.setIsHot(isHot);
        boolean result = this.updateById(activity);
        return result;
    }

    @Override
    public List<ActivityVO> getHotActivityList() {
        LambdaQueryWrapper<Activity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Activity::getIsHot, 1);
        List<Activity> activities = this.list(queryWrapper);
        List<ActivityVO> activityVOList = activities.stream().map(activity -> {
            ActivityVO activityVO = new ActivityVO();
            BeanUtil.copyProperties(activity, activityVO);
            return activityVO;
        }).collect(Collectors.toList());
        return activityVOList;
    }

    @Override
    public RegistrationVO registration(Integer activityId) {
        Activity activity = this.getById(activityId);
        Assert.notNull(activity, "活动不存在");
        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String activityTime = (activity.getStartTime() != null && activity.getEndTime() != null)
                ? String.format("%s 至 %s",
                activity.getStartTime().format(dateFormatter),
                activity.getEndTime().format(dateFormatter))
                : "无活动时间";

        LambdaQueryWrapper<ActivityRegistration> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ActivityRegistration::getIsPaid,PaymentStatus.PAID);
        queryWrapper.eq(ActivityRegistration::getActivityId, activity.getId());
        queryWrapper.ne(ActivityRegistration::getStatus, RegistrationEnum.CANCELLED);//排除已取消的报名
        List<ActivityRegistration> activityRegistrationList = activityRegistrationService.list(queryWrapper);

        List<Integer> userIds = activityRegistrationList.stream().map(ActivityRegistration::getUserId)
                .filter(Objects::nonNull).toList();
        Map<Integer,User> userMap;
        if(!userIds.isEmpty()){
            userMap = userService.listByIds(userIds).stream().collect(Collectors.toMap(User::getId, e -> e));
        } else {
            userMap = new HashMap<>();
        }

        List<ActivityRegistrationVO> activityRegistrationVOList = activityRegistrationList.stream().map(activityRegistration -> {
            ActivityRegistrationVO activityRegistrationVO = new ActivityRegistrationVO();
            //获取用户ID
            Integer userId = activityRegistration.getUserId();
            activityRegistrationVO.setActivityTitle(activity.getTitle());
            BeanUtil.copyProperties(activityRegistration, activityRegistrationVO);
            activityRegistrationVO.setActivityAddress(activity.getActivityAddress());
            activityRegistrationVO.setActivityTime(activityTime);
            return activityRegistrationVO;
        }).collect(Collectors.toList());

        ActivityVO activityVO = new ActivityVO();
        BeanUtil.copyProperties(activity, activityVO);

        RegistrationVO registrationVO = new RegistrationVO();
        BeanUtil.copyProperties(activityVO, registrationVO);
        registrationVO.setRegistrations(activityRegistrationVOList);

        return registrationVO;
    }

    @Override
    public Boolean audit(ActivityRegistrationAuditDTO auditDTO) {
        Integer activityId = auditDTO.getActivityId();
        Activity activity = this.getById(activityId);
        Assert.notNull(activity, "活动不存在");
        Integer status = auditDTO.getStatus();
        Integer userId = auditDTO.getUserId();
        String orderNo = auditDTO.getOrderNo();
        //取消报名，积分或微信支付发起退款流程
        if (status != null && status.equals(RegistrationEnum.CANCELLED.getCode())){
             return this.refund(activityId,userId,orderNo,StrUtil.isBlank(auditDTO.getReviewReason()) ? "审核不通过" : auditDTO.getReviewReason());
        }
        LambdaQueryWrapper<ActivityRegistration> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ActivityRegistration::getActivityId, activityId)
                .eq(ActivityRegistration::getUserId, userId)
                .eq(ActivityRegistration::getOrderNo, orderNo);

        ActivityRegistration activityRegistration = activityRegistrationService.getOne(queryWrapper)
                .setStatus(RegistrationEnum.getByCode(status))
                .setReviewReason(StrUtil.isBlank(auditDTO.getReviewReason()) ? "审核通过" : auditDTO.getReviewReason());
        return activityRegistrationService.updateById(activityRegistration);
    }

    @Override
    public List<ActivityVO> activityList() {
        List<Activity> activities = this.list();
        List<ActivityVO> activityVOS = activities.stream().map(activity -> {
            ActivityVO activityVO = new ActivityVO();
            BeanUtil.copyProperties(activity, activityVO);
            return activityVO;
        }).collect(Collectors.toList());
        return activityVOS;
    }

    /**
     * 创建活动报名订单
     *
     * @param activityId
     * @return
     */
    @Override
    @SneakyThrows
    public ActivityOrderRsp generateOrder(Integer activityId) {
        Activity activity = this.lambdaQuery()
                .eq(Activity::getId, activityId)
                .ge(Activity::getEndTime, LocalDateTime.now()) //活动未结束
                .eq(Activity::getIsFull,0)
                .one();
        Assert.notNull(activity, "活动不存在或已结束");

        //检查名额是否足够
        if (!"不限".equals(activity.getQuota())) {
            int quota = Integer.parseInt(activity.getQuota());
            Assert.isTrue(quota > activity.getRegistered(), "剩余名额不足！");
        }

        String orderNO;
        ActivityRegistration registration;
        do {
            orderNO = RandomStringUtils.randomAlphanumeric(16).toUpperCase();
            registration = activityRegistrationService.lambdaQuery()
                    .eq(ActivityRegistration::getOrderNo, orderNO)
                    .one();
        } while (registration != null);

        ActivityOrderRsp orderRsp = ActivityOrderRsp.builder()
                .activityId(activityId)
                .orderNO(orderNO)
                .paymentType(activity.getPaymentType().getCode())
                .totalAmount(activity.getPaymentType().getCode() == 0 ? BigDecimal.ZERO : activity.getPaymentAmount())
                .build();

        String key = String.format(ACTIVITY_ORDER_PREFIX, PrincipalUtil.getId(), orderNO);
        redisTemplate.opsForValue().set(key, objectMapper.writeValueAsString(orderRsp));
        redisTemplate.expire(key, 30, TimeUnit.MINUTES);

        return orderRsp;
    }

    /**
     * 支付活动报名订单
     *
     * @param activityRegistrationOrder
     * @return
     */
    @Override
    @SneakyThrows
    @Transactional
    public ActivityOrderPayRsp pay(ActivityRegistrationOrder activityRegistrationOrder) {
        String key = String.format(ACTIVITY_ORDER_PREFIX,PrincipalUtil.getId(),activityRegistrationOrder.getOrderNO());
        String orderStr = redisTemplate.opsForValue().get(key);
        Assert.notBlank(orderStr, "订单已过期，请重新下单");

        //从redis中解析
        ActivityOrderRsp  order = objectMapper.readValue(orderStr, ActivityOrderRsp.class);
        //获取活动信息
        Activity activity = this.getById(order.getActivityId());
        //获取用户信息
        User user = userMapper.selectById(PrincipalUtil.getId());

        //判断一下该用户是否已经报过名
        ActivityRegistration activityRegistration = activityRegistrationService.lambdaQuery()
                .eq(ActivityRegistration::getIsPaid, PaymentStatus.PAID) //已支付
                .eq(ActivityRegistration::getActivityId, order.getActivityId())
                .eq(ActivityRegistration::getUserId, activityRegistrationOrder.getUserId())
                .one();
        Assert.isNull(activityRegistration, "您已经报名过该活动，请勿重复报名");

        //获取支付方式
        PaymentTypeEnums paymentType = PaymentTypeEnums.getByCode(order.getPaymentType());

        //创建报名记录（初始化状态为未支付）
        ActivityRegistration  registration  = createRegistrationRecord(activityRegistrationOrder,activity,paymentType);

        boolean saveSuccess = activityRegistrationService.save(registration);
        Assert.isTrue(saveSuccess, "报名失败，请稍后重试");

        //根据支付类型处理
        switch (paymentType) {
            case FREE: //免费
                return processFreePayment(registration,activity);
            case POINTS: //积分
                return processPointsPayment(registration,activity,user);
            case MONEY: //微信支付
                return processWechatPayment(registration,activity,user);
            default:
                throw new IllegalStateException("不支持的支付类型");
        }
    }

    /**
     * 处理微信支付
     * @param registration
     * @param activity
     * @param user
     * @return
     */
    private ActivityOrderPayRsp processWechatPayment(ActivityRegistration registration, Activity activity, User user) {
        try{
            //修改：支付前只检查名额，不实际占用
            if(!checkQuotaAvailable(activity.getId())){
                //更新报名记录状态为失败
                updateRegistrationToFailed(registration.getId());
                return ActivityOrderPayRsp.fail("名额已满，支付失败");
            }
            //更新报名记录状态为待支付（微信支付中）
            registration.setIsPaid(PaymentStatus.PENDING);//待支付
            registration.setPaymentType(PaymentTypeEnums.MONEY);
            boolean updatePending = activityRegistrationService.updateById(registration);
            if(!updatePending){
                //如果更新失败，回滚名额
//                rollbackQuota(activity.getId());
                //如果更新失败，直接返回失败，无需回滚名额
                updateRegistrationToFailed(registration.getId());
                return ActivityOrderPayRsp.fail("订单状态更新失败");
            }

            //调用微信支付下单
            int totalFee = activity.getPaymentAmount().multiply(Constants.ONE_HUNDRED).intValue();

            WxPayUnifiedOrderRequest request = WxPayUnifiedOrderRequest.newBuilder()
                    .outTradeNo(registration.getOrderNo())
                    .totalFee(totalFee)
                    .openid(user.getWxOpenId())
                    .tradeType("JSAPI")
                    .body(activity.getTitle())
                    .timeExpire(LocalDateTime.now().plusMinutes(30)
                            .format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")))
                    .spbillCreateIp(IpUtil.getRemoteIp(RequestUtil.getRequest()))
                    .notifyUrl(wxProperty.getActivityPayNotifyUrl())
                    .build();

            WxPayMpOrderResult payOrderResult = wxPayService.createOrder(request);

            ActivityOrderPayRsp activityOrderPayRsp = BeanUtil.copyProperties(payOrderResult, ActivityOrderPayRsp.class);
            activityOrderPayRsp.setOrderId(registration.getId());
            return activityOrderPayRsp;
        } catch (Exception e) {
            log.error("微信支付下单失败", e);
            // 更新报名记录状态为失败
            updateRegistrationToFailed(registration.getId());
            return ActivityOrderPayRsp.fail("微信支付下单失败");
        }
    }

    /**
     * 检查名额是否可用（不实际占用）
     * @param activityId
     * @return
     */
    private boolean checkQuotaAvailable(Integer activityId) {
        Activity activity = this.getById(activityId);
        if("不限".equals(activity.getQuota())){
            return true;
        }else {
            //检查是否还有名额,不实际占用
            int quota = Integer.parseInt(activity.getQuota());
            Integer currentRegistered = this.lambdaQuery()
                    .select(Activity::getRegistered)
                    .eq(Activity::getId, activityId)
                    .one()
                    .getRegistered();
            return currentRegistered < quota;
        }
    }

    /**
     * 积分支付处理
     * @param registration
     * @param activity
     * @param user
     * @return
     */
    private ActivityOrderPayRsp processPointsPayment(ActivityRegistration registration, Activity activity, User user) {
        RLock lock = redissonClient.getFairLock(PAY_NOTIFY_LOCK + user.getId());
        boolean locked = false;

        try {
            //获取分布式锁,防止并发扣积分
            locked = lock.tryLock(5, 5, TimeUnit.SECONDS);
            if(!locked) {
                // 更新报名记录状态为失败
                updateRegistrationToFailed(registration.getId());
                return ActivityOrderPayRsp.fail("系统繁忙，请稍后重试");
            }
            //1.检查积分是否足够
            Integer credit = user.getCredit();
            int requiredPoints  = activity.getPaymentAmount().intValue();
            if(credit < requiredPoints) {
                // 更新报名记录状态为失败
                updateRegistrationToFailed(registration.getId());
                return ActivityOrderPayRsp.fail("积分不足，支付失败");
            }

            //2.占用名额
            if(!occupyQuota(activity.getId())) {
                //更新报名记录状态为失败
                updateRegistrationToFailed(registration.getId());
                return ActivityOrderPayRsp.fail("名额已满，支付失败");
            }

            //3.扣减积分
            user.setCredit(credit - requiredPoints);
            int updateUserResult = userMapper.updateById(user);
            if(updateUserResult <= 0) {
                //回滚名额并更新报名状态
                rollbackQuotaAndUpdateRegistration(registration.getId(),activity.getId());
                return ActivityOrderPayRsp.fail("积分扣减失败");
            }

            //4.更新报名状态为成功
            registration.setIsPaid(PaymentStatus.PAID);
            registration.setPaymentTime(LocalDateTime.now());
            boolean updateRegistration = activityRegistrationService.updateById(registration);
            if(!updateRegistration){
                //回滚积分、名额并更新报名状态
                user.setCredit(credit);
                userMapper.updateById(user);
                rollbackQuotaAndUpdateRegistration(registration.getId(),activity.getId());
                return ActivityOrderPayRsp.fail("报名状态更新失败");
            }

            //5.保存积分流水
            try{
                creditFlowService.save(new CreditFlow()
                        .setUserId(registration.getUserId())
                        .setBusinessId(registration.getId())
                        .setBusinessType(EFlowBusinessType.ACTIVITY_ORDER_PAYMENT.getValue())
                        .setFlowType(EFlowType.CONSUME.getValue())
                        .setCredit(-requiredPoints));
            } catch (Exception e) {
                log.error("保存积分流水失败,但支付已完成",e);
            }
            log.info("积分支付成功，registrationId: {},消耗积分：{}", registration.getId(),requiredPoints);
            return ActivityOrderPayRsp.success();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            //更新报名状态为失败
            updateRegistrationToFailed(registration.getId());
            return ActivityOrderPayRsp.fail("系统繁忙，请稍后重试");
        }catch (Exception e) {
            log.error("积分支付处理异常",e);
            //回滚名额并更新报名状态
            rollbackQuotaAndUpdateRegistration(registration.getId(),activity.getId());
            return ActivityOrderPayRsp.fail("支付处理异常");
        }finally {
            if(locked) {
                lock.unlock();
            }
        }
    }

    /**
     * 处理免费支付
     * @param registration
     * @param activity
     * @return
     */
    private ActivityOrderPayRsp processFreePayment(ActivityRegistration registration, Activity activity) {
        try{
            //1.占用名额
            if(!occupyQuota(activity.getId())) {
                //更新报名记录
                updateRegistrationToFailed(registration.getId());
                return ActivityOrderPayRsp.fail("名额已满，支付失败");
            }

            //2.更新报名状态为成功
            registration.setIsPaid(PaymentStatus.PAID);
            registration.setPaymentTime(LocalDateTime.now());
            boolean updateSuccess = activityRegistrationService.updateById(registration);

            if(updateSuccess) {
                log.info("免费支付成功，registrationId: {}", registration.getId());
                return ActivityOrderPayRsp.success();
            } else {
                //如果更新失败，需要回滚名额并更新报状态
                rollbackQuotaAndUpdateRegistration(registration.getId(),activity.getId());
                return ActivityOrderPayRsp.fail("支付状态更新失败");
            }
        }catch (Exception e) {
            log.error("免费支付处理异常",e);
            rollbackQuotaAndUpdateRegistration(registration.getId(),activity.getId());
            return ActivityOrderPayRsp.fail("支付处理异常");
        }
    }

    /**
     * 回滚名额并更新报名状态
     * @param registrationId
     * @param activityId
     */
    private void rollbackQuotaAndUpdateRegistration(Integer registrationId, Integer activityId) {
        try{
            //先回滚名额
            rollbackQuota(activityId);
            //再更新报名记录状态
            updateRegistrationToFailed(registrationId);
            log.info("名额回滚和报名状态更新成功，registrationId:{},activityId: {}",registrationId,activityId);
        } catch (Exception e){
            log.error("名额回滚和报名状态更新失败，registrationId:{},activityId: {}",registrationId,activityId,e);
        }
    }

    /**
     * 回滚名额（补偿操作）
     * @param activityId
     */
    private void rollbackQuota(Integer activityId) {
        try{
            this.lambdaUpdate()
                    .setSql("registered = GREATEST(registered - 1, 0)") //防止减至负数
                    .setSql("is_full = 0") //重置满额状态
                    .eq(Activity::getId, activityId)
                    .update();
            log.info("名额回滚成功,activityId:{}",activityId);
        }catch (Exception e){
            log.error("名额回滚失败,activityId:{}",activityId,e);
        }
    }

    /**
     * 更新报名记录状态为失败
     * @param registrationId
     */
    private void updateRegistrationToFailed(Integer registrationId) {
        try{
            ActivityRegistration update = new ActivityRegistration();
            update.setId(registrationId);
            update.setStatus(RegistrationEnum.CANCELLED);
            update.setIsPaid(PaymentStatus.NOT_PAID);//未支付
            boolean updated = activityRegistrationService.updateById(update);
            if(updated){
                log.info("报名记录状态更新为失败，registrationId: {}", registrationId);
            } else {
                log.warn("报名记录状态更新失败，记录可能不存在，registrationId: {}", registrationId);
            }
        } catch (Exception e) {
            log.error("报名记录状态更新异常，registrationId:{}",registrationId,e);
        }
    }

    /**
     * 统一的占用名额方法
     * @param activityId
     * @return
     */
    private boolean occupyQuota(Integer activityId) {
        Activity activity = this.getById(activityId);
        if("不限".equals(activity.getQuota())) {
            return this.lambdaUpdate()
                    .setSql("registered = registered + 1")
                    .eq(Activity::getId, activityId)
                    .update();
        } else {
            return this.lambdaUpdate()
                    .setSql("registered = registered + 1")
                    .setSql("is_full = CASE WHEN registered + 1 >= CAST(quota AS SIGNED) THEN 1 ELSE is_full END")
                    .eq(Activity::getId, activityId)
                    .apply("registered < CAST(quota AS SIGNED)")
                    .update();
        }
    }

    /**
     * 创建报名记录
     * @param order
     * @param activity
     * @param paymentType
     * @return
     */
    private ActivityRegistration createRegistrationRecord(ActivityRegistrationOrder order, Activity activity, PaymentTypeEnums paymentType) {
        ActivityRegistration registration = new ActivityRegistration();
        registration.setActivityId(activity.getId());
        registration.setUserId(order.getUserId());
        registration.setName(order.getName());
        registration.setPhone(order.getPhone());
        registration.setOrderNo(order.getOrderNO());
        registration.setNumber(1);
        registration.setStatus(RegistrationEnum.PENDING); // 待确认
        registration.setPaymentType(paymentType);
        registration.setPaymentAmount(activity.getPaymentAmount());
        registration.setIsRefunded(RefundStatus.NOT_REFUNDED); // 未退款
        registration.setIsPaid(PaymentStatus.NOT_PAID); // 未支付
        return registration;
    }


    /**
     * 微信支付回调
     *
     * @param notifyResutl
     * @return
     */
    @SneakyThrows
    @Override
    public String wechatPayNotify(String notifyResutl) {
        log.info("微信支付回调：{}", notifyResutl);
        WxPayOrderNotifyResult result = wxPayService.parseOrderNotifyResult(notifyResutl);
        result.checkResult(wxPayService,result.getSignType(),true);

        RLock lock = redissonClient.getFairLock(PAY_NOTIFY_LOCK + result.getOutTradeNo());
        boolean locked = false;

        try {
            locked = lock.tryLock(5,5,TimeUnit.SECONDS);
            if(!locked){
                log.warn("获取支付回调锁失败，orderNO:{}",result.getOutTradeNo());
                return WxPayNotifyResponse.fail("处理中，请销后");
            }

            String orderNo = result.getOutTradeNo();
            ActivityRegistration activityRegistration = activityRegistrationService.lambdaQuery()
                    .eq(ActivityRegistration::getOrderNo, orderNo)
                    .one();

            if (activityRegistration == null) {
                return WxPayNotifyResponse.fail("订单不存在");
            }

            //检查是否已经处理过
            if(activityRegistration.getIsPaid() == PaymentStatus.PAID){
                log.info("订单已处理，orderNO:{}",result.getOutTradeNo());
                return WxPayNotifyResponse.success("订单已处理");
            }

            //检查订单状态是滞为待支付(防止重复处理）
            if(activityRegistration.getIsPaid() != PaymentStatus.PENDING) {
                log.warn("订单状态异常，期望状态为待支付，实际状态：{},orderNo:{}",activityRegistration.getIsPaid(),orderNo);
                return WxPayNotifyResponse.fail("订单状态异常");
            }

            // 修改：支付成功后才实际占用名额
            boolean occupySuccess = occupyQuota(activityRegistration.getActivityId());
            if(!occupySuccess){
                log.warn("支付回调中名额已满，用户成为超出人员，orderNO:{}",result.getOutTradeNo());
//                updateRegistrationToOverQuota(activityRegistration.getId());
//                return WxPayNotifyResponse.success("订单处理成功");
            }
            //2.更新报名状态为成功
            ActivityRegistration update = new ActivityRegistration();
            update.setId(activityRegistration.getId());
            update.setStatus(RegistrationEnum.PENDING);//待确认
            update.setIsPaid(PaymentStatus.PAID);//已付款
            update.setIsRefunded(RefundStatus.NOT_REFUNDED);//未退款
            update.setPaymentTime(LocalDateTime.now());
            update.setPaymentType(PaymentTypeEnums.MONEY);

            boolean updated = activityRegistrationService.updateById(update);
            if(!updated){
                log.error("订单状态更新失败，orderNo: {}", orderNo);
                // 注意：这里不返回失败，因为支付已成功
                //return WxPayNotifyResponse.fail("订单状态更新失败");
            }
            log.info("微信支付调处理成功,orderNO:{}",orderNo);
            return WxPayNotifyResponse.success("订单处理成功");

        }catch (InterruptedException  e) {
            Thread.currentThread().interrupt();
            return WxPayNotifyResponse.fail("处理中断");
        }catch (Exception e){
            log.error("微信支付回调处理异常",e);
            return WxPayNotifyResponse.fail("处理异常");
        }finally {
            if(locked){
                lock.unlock();
            }
        }
    }

    /**
     * 更新报名记录状态为超出名额
     * @param registrationId
     */
    private void updateRegistrationToOverQuota(Integer registrationId) {
        try{
            ActivityRegistration update = new ActivityRegistration();
            update.setId(registrationId);
            update.setStatus(RegistrationEnum.PENDING);//待确认
            update.setIsPaid(PaymentStatus.PAID);//已付款
            update.setIsRefunded(RefundStatus.NOT_REFUNDED);//未退款
            update.setPaymentTime(LocalDateTime.now());
            update.setPaymentType(PaymentTypeEnums.MONEY);//微信支付
            update.setAuditRemark("支付成功，但名额已满，用户成为超出人员，是否需要退款处理");

            boolean updated = activityRegistrationService.updateById(update);
            if(updated){
                log.info("报名记录状态更新为超出名额，registrationId: {}", registrationId);
            } else {
                log.warn("报名记录状态更新失败，记录可能不存在，registrationId: {}", registrationId);
            }
        }catch (Exception e){
            log.error("报名记录状态更新异常，registrationId:{}",registrationId,e);
        }
    }

    /**
     * 活动-微信退款回调
     *
     * @param notifyResutl
     * @return
     */
    @SneakyThrows
    @Override
    @Transactional
    public String wechatRefundNotify(String notifyResutl) {
        log.info("活动-微信退款回调:{}", notifyResutl);
        try {
            //解析退款回调数据
            WxPayRefundNotifyResult result = wxPayService.parseRefundNotifyResult(notifyResutl);

            RLock lock = redissonClient.getFairLock(REFUND_NOTIFY_LOCK);
            boolean locked = false;
            try {
                lock.tryLock(2, 2, TimeUnit.SECONDS);
                locked = true;

                String outTradeNo = result.getReqInfo().getOutRefundNo();
                String outRefundNo = result.getReqInfo().getOutRefundNo();

                //根据订单号查询活动人员信息
                ActivityRegistration activityRegistration = activityRegistrationService.lambdaQuery()
                        .eq(ActivityRegistration::getOrderNo, outTradeNo)
                        .one();

                if (activityRegistration == null) {
                    return WxPayNotifyResponse.fail("订单不存在");
                }
                //检查退款状态
                if ("SUCCESS".equals(result.getReqInfo().getRefundStatus())) {
                    //退款成功
                    ActivityRegistration update = new ActivityRegistration();
                    update.setIsPaid(PaymentStatus.CANCELLED);
                    update.setIsRefunded(RefundStatus.REFUNDED);
                    update.setRefundTime(LocalDateTime.now());
                    update.setRefundTransactionId(result.getReqInfo().getRefundId());
                    update.setId(activityRegistration.getId());

                    activityRegistrationService.updateById(update);

                    //退还库存
                    this.lambdaUpdate()
//                            .setSql("registered = registered - 1")
                            .setSql("registered = GREATEST(registered - 1, 0)") //防止减至负数
                            .set(Activity::getIsFull,0)//重置为未报满状态
                            .eq(Activity::getId, activityRegistration.getActivityId())
                            .update();
                    log.info("退款成功，订单号：{}，退款单号：{}", outTradeNo, outRefundNo);
                } else if("FAIL".equals(result.getReqInfo().getRefundStatus())){
                    //退款失败
                    activityRegistrationService.lambdaUpdate()
                            .set(ActivityRegistration::getIsRefunded, 0)
                            .set(ActivityRegistration::getRefundTime, LocalDateTime.now())
                            .set(ActivityRegistration::getAuditRemark,"微信退款失败：" + result.getReqInfo().getRefundStatus())
                            .eq(ActivityRegistration::getId, activityRegistration.getId())
                            .update();
                    log.error("退款失败，订单号：{}，退款单号：{}，状态：{}", outTradeNo, outRefundNo, result.getReqInfo().getRefundStatus());
                }
                return WxPayNotifyResponse.success("退款回调已处理");
            } catch (IllegalStateException e) {
                log.error("加锁失败", e);
                throw e;
            } finally {
                if (locked) {
                    lock.unlock();
                }
            }
        } catch (Exception e) {
            log.error("退款回调处理失败", e);
            return WxPayNotifyResponse.fail("退款回调处理失败" + e.getMessage());
        }
    }

    /**
     * 活动退款
     * @param registrationId 报名名ID
     * @return
     */
    @Override
    @Transactional
    @SneakyThrows
    public Boolean refund(int registrationId,Integer userId,String orderNo,String reviewReason) {
        //获取报名信息
//        ActivityRegistration registration = activityRegistrationService.getById(registrationId);
        ActivityRegistration registration = activityRegistrationService.lambdaQuery()
                .eq(ActivityRegistration::getActivityId, registrationId)
                .eq(ActivityRegistration::getUserId, userId)
                .eq(ActivityRegistration::getOrderNo, orderNo)
                .one();
        Assert.notNull(registration, "报名信息不存在");
        //获取活动信息
        Activity activity = this.getById(registration.getActivityId());
        Assert.notNull(activity, "活动不存在");

        //检查是否可以退款
//        Assert.isTrue(registration.getStatus() == RegistrationEnum.CONFIRMED,"只有已确认的报名可以退款");
        PaymentTypeEnums paymentType = registration.getPaymentType();
        if(paymentType != PaymentTypeEnums.MONEY){
            boolean update = this.lambdaUpdate()
//                    .setSql("registered = registered - 1")
                    .setSql("registered = GREATEST(registered - 1, 0)") //防止减至负数
                    .set(Activity::getIsFull,0) //重置为未报满状态
                    .eq(Activity::getId, activity.getId())
                    .update();

            Assert.isTrue(update,"报名人数更新失败");
        }
        //更新报名状态为已取消
        registration.setStatus(RegistrationEnum.CANCELLED);
//        registration.setRefundTime(LocalDateTime.now());
        registration.setReviewReason(reviewReason);
//        boolean regResult = activityRegistrationService.updateById(registration);

        switch (paymentType){
            case FREE:
                registration.setStatus(RegistrationEnum.CANCELLED);
                registration.setIsPaid(PaymentStatus.CANCELLED);
                registration.setIsRefunded(RefundStatus.REFUNDED);
                registration.setRefundTime(LocalDateTime.now());
                boolean result = activityRegistrationService.updateById(registration);
                Assert.isTrue(result,"报名信息审核失败,请重试！");
                return result;
            case POINTS:
                registration.setStatus(RegistrationEnum.CANCELLED);
                registration.setIsPaid(PaymentStatus.CANCELLED);
                registration.setIsRefunded(RefundStatus.REFUNDED);
                registration.setRefundTime(LocalDateTime.now());
                boolean pointReg = activityRegistrationService.updateById(registration);
                Assert.isTrue(pointReg,"报名信息审核失败,请重试！");
                //获取用户id
                User user = userService.getById(registration.getUserId());
                //获取积分金额
                BigDecimal paymentAmount = registration.getPaymentAmount();
                //积分退款
                User update = new User();
                update.setId(userId);
                update.setCredit(user.getCredit() + paymentAmount.intValue());
                boolean userResult = userService.updateById(update);

                Assert.isTrue(userResult,"积分退款失败：用户积分更新失败");
                //保存流水
                CreditFlow flow = new CreditFlow()
                        .setUserId(userId)
                        .setBusinessId(registration.getId())
                        .setBusinessType(EFlowBusinessType.CREDIT_ORDER_REFUND.getValue())
                        .setFlowType(EFlowType.OBTAIN.getValue())
                        .setCredit(paymentAmount.intValue());
                boolean flowResult = creditFlowService.save(flow);
                Assert.isTrue(flowResult,"积分退款失败：流水记录保存失败");
                return flowResult;
            case MONEY:
                //取消
                registration.setStatus(RegistrationEnum.CANCELLED);
                //未支付
                registration.setIsPaid(PaymentStatus.CANCELLED);
                registration.setIsRefunded(RefundStatus.NOT_REFUNDED);
                boolean regResult = activityRegistrationService.updateById(registration);
                //调用微信退款接口
                int refundFee = activity.getPaymentAmount().multiply(Constants.ONE_HUNDRED).intValue();

                WxPayRefundRequest refundRequest = WxPayRefundRequest.newBuilder()
                        .outTradeNo(registration.getOrderNo())
                        .outRefundNo("RF" + registration.getOrderNo())
                        .totalFee(refundFee)
                        .refundFee(refundFee)
                        .refundDesc("活动退款")
                        .notifyUrl(wxProperty.getActivityRefundNotifyUrl())
                        .build();
                wxPayService.refund(refundRequest);

//                registration.setIsRefunded(RefundStatus.NOT_REFUNDED); //待退款
                return regResult;
                default:
                    throw new IllegalStateException("不支持的支付类型");
        }
    }

    @Override
    @SneakyThrows
    public void export(HttpServletResponse response, Integer activityId) {
        Activity activity = this.getById(activityId);
        Assert.notNull(activity, "活动不存在");
        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String activityTime = (activity.getStartTime() != null && activity.getEndTime() != null)
                ? String.format("%s 至 %s",
                activity.getStartTime().format(dateFormatter),
                activity.getEndTime().format(dateFormatter))
                : "无活动时间";

        LambdaQueryWrapper<ActivityRegistration> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ActivityRegistration::getActivityId, activity.getId());
        queryWrapper.eq(ActivityRegistration::getStatus, RegistrationEnum.CONFIRMED.getCode());
        //获取报名人员列表信息
        List<ActivityRegistration> activityRegistrationList = activityRegistrationService.list(queryWrapper);

        List<Integer> userIds = activityRegistrationList.stream().map(ActivityRegistration::getUserId)
                .filter(Objects::nonNull).toList();

        List<ActivityRegistrationExcel> results = new ArrayList<>();

        for (ActivityRegistration activityRegistration : activityRegistrationList) {
            ActivityRegistrationExcel activityRegistrationExcel = new ActivityRegistrationExcel();
            BeanUtil.copyProperties(activityRegistration, activityRegistrationExcel);
            activityRegistrationExcel.setActivityTitle(activity.getTitle());
            activityRegistrationExcel.setActivityTime(activityTime);
            activityRegistrationExcel.setActivityAddress(activity.getActivityAddress());
            activityRegistrationExcel.setStatus(activityRegistration.getStatus().getDesc());
            activityRegistrationExcel.setPaymentType(activityRegistration.getPaymentType().getDesc());

            activityRegistrationExcel.setIsPaid(activityRegistration.getIsPaid().getDesc());
            activityRegistrationExcel.setIsRefunded(activityRegistration.getIsRefunded().getDesc());
            results.add(activityRegistrationExcel);
        }

        ExcelUtil.write(results, ActivityRegistrationExcel.class, response,"活动报名信息" );
    }

    /**
     * 检查热门活动数量是否超过限制
     */
    private void checkHostActivityLimit() {
        //查询当前热门活动数量
        LambdaQueryWrapper<Activity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Activity::getIsHot, 1);
        long hotCount = this.count(queryWrapper);
        Assert.isFalse(hotCount >= MAX_HOT_ACTIVITIES, "热门活动数量不能超过" + MAX_HOT_ACTIVITIES + "个");
    }

    /**
     * 格式化时间范围
     *
     * @param startTime
     * @param endTime
     * @return
     */
    private static String formatTimeRange(LocalDateTime startTime, LocalDateTime endTime) {
        return Optional.ofNullable(startTime)
                .flatMap(start -> Optional.ofNullable(endTime)
                        .map(end -> formatDateTime(start) + " - " + formatDateTime(end)))
                .orElse("");
    }

    /**
     * 安全格式化日期(如果为null返回空字符串)
     *
     * @param dateTime
     * @return
     */
    private static String formatDateTime(LocalDateTime dateTime) {
        return Optional.ofNullable(dateTime)
                .map(DEFAULT_FORMATTER::format)
                .orElse("");
    }
}
